package com.terrace.web.aspect.logs;

import java.lang.reflect.Method;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.aspectj.lang.JoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.terrace.web.annotation.Logs;
import com.terrace.db.system.mapper.entity.LogWithDetails;
import com.terrace.core.common.model.UserInfo;
import com.terrace.db.system.service.LogService;
import com.terrace.core.utils.BrowserUtils;
import com.terrace.core.utils.IpUtils;
import com.terrace.core.utils.JsonUtils;
import com.terrace.core.utils.reflect.ReflectUtils;
import com.terrace.web.constant.GlobalsConstant;
import com.terrace.web.exception.CustomLogsException;

/**
 * 记录日志
 * @author jiangyg
 *
 */
public class LogsAspect {

	/**
	 * 日志
	 */
	private static final Logger logger = LoggerFactory.getLogger(LogsAspect.class);
	
	@Autowired
	private LogService logService;
	
	/**
	 * 方法返回通知
	 * @param joinPoint
	 */
	public void doLogsAfterReturning(JoinPoint joinPoint, Object returnValue) {
		writeLogs(joinPoint, returnValue);
	}
	
	/**
	 * 方法抛出异常通知
	 * @param joinPoint
	 */
	public void doLogsAfterThrowing(JoinPoint joinPoint, Throwable ex) {
		writeLogs(joinPoint, ex.getMessage());
	}
	
	/**
	 * 写日志
	 * @param joinPoint
	 * @param result
	 */
	private void writeLogs(JoinPoint joinPoint, Object result) {
		try {
			
			String targetName = joinPoint.getTarget().getClass().toString();
			String methodName = joinPoint.getSignature().getName();
			Object[] arguments = joinPoint.getArgs();
			Method[] methods = joinPoint.getTarget().getClass().getMethods();

			// 获取日志配置信息
			Logs logs = ReflectUtils.obtainAnnotation(methodName, Logs.class, methods, arguments);;
			
			if (logs != null) {
				
				HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
				
				if (request == null) {
					throw new CustomLogsException("日志AOP[" + targetName + "][" + methodName + "]未正确获取到request。");
				}
				
				// 用户信息
				String userId = null;
				Session session =SecurityUtils.getSubject().getSession();
				if (session != null) {
					UserInfo userInfo = (UserInfo) session.getAttribute(GlobalsConstant.USER_SESSION_KEY);
					if (userInfo != null) {
						userId = userInfo.getUserId();
					}
				}
				
				LogWithDetails log = new LogWithDetails();
				log.setUserId(userId);
				log.setLogDepict(logs.depict());
				log.setOperateType(logs.type());
				log.setOperateBroswer(BrowserUtils.checkBrowse(request));
				log.setOperateIp(IpUtils.getIpAddr(request));
				log.setOperateTime(new Date());
				// 请求参数
				log.setRequestDetails(objectToJsonBytes(request.getParameterMap()));
				// 响应结果
				log.setResponseDetails(objectToJsonBytes(result));
				
				// 保存日志
				logService.saveLogSelective(log);
				
				if (logger.isDebugEnabled()) {
					logger.debug("记录日志：[" + JsonUtils.beanToJson(log) + "]");
				}
				
			}
			
		} catch (Exception e) {
			logger.error("日志记录出错：", e);
		}
	}
	
	/**
	 * 对象转换json形式的byte数组
	 * @param obj
	 * @return
	 */
	private byte[] objectToJsonBytes(Object obj) {
		byte[] result = null;
		if (obj != null && !(obj instanceof String)) {
			String json = JsonUtils.beanToJson(obj);
			if (StringUtils.isNotBlank(json)) {
				result = json.getBytes();
			}
		} else {
			result = ObjectUtils.toString(obj).getBytes();
		}
		return result;
	}

}
